#include"mpu6050.h"

#define MPU6050_NUM 1
#define MPU6050_NAME "mpu6050"

struct MPU6050
{
    dev_t devid;
    int major;
    int minor;
    struct cdev mpu6050_cdev;
    struct class *class;
    struct device *device;
    struct i2c_client *client;
};

static struct MPU6050 mpu6050;

/*Reads the register values in one transaction or returns a negative
 *	error code on failure.*/
static int mpu6050_readReg(struct i2c_client *client,u8 reg,u8 *buffer, int length)
{
    	struct i2c_msg msg[] = {
		{
			.addr = client->addr,
			.flags = 0,
			.len = 1,
			.buf = &reg,
		},
		{
			.addr = client->addr,
			.flags = I2C_M_RD,
			.len = length,
			.buf = buffer,
		},
	};
    return i2c_transfer(client->adapter, msg, 2);
}
static int mpu6050_writeReg(struct i2c_client *client,u8 reg,u8 *buffer, int length)
{
        u8 data[64];
        data[0]=reg;
        memcpy(&data[1],buffer,length);

    	struct i2c_msg msg[] = {
		{
			.addr = client->addr,
			.flags = 0,
			.len = length+1,
			.buf = data,
		},
	};
    return i2c_transfer(client->adapter, msg, 1);
}

static int mpu6050_readByte(struct i2c_client *client,u8 reg,u8 *buffer)
{
    return mpu6050_readReg(client,reg,buffer,1);
}
static int mpu6050_writeByte(struct i2c_client *client,u8 reg,u8 buffer)
{
    return mpu6050_writeReg(client,reg,&buffer,1);
}

static int mpu6050_release (struct inode * node, struct file *file)
{
    return 0;
}
static int mpu6050_open (struct inode *node, struct file *file)
{
    return 0;
}

static ssize_t mpu6050_write (struct file *file, const char __user *buffer, size_t size, loff_t *loff)
{
    printk("write\r\n");
    return 0;
}
static 	ssize_t mpu6050_read (struct file *file, char __user *buffer, size_t size, loff_t *loff)
{
    short Data[6];
    int ret =0;
	uint8_t buff[6];
	
    while(mpu6050_readReg(mpu6050.client,MPU6050_ACCEL_XOUT_H,buff,6)<0);

    Data[0]=(buff[0] << 8)|buff[1];
	Data[1]=(buff[2]<<8)|buff[3];
    Data[2]=(buff[4]<<8)|buff[5];

    while(mpu6050_readReg(mpu6050.client,MPU6050_GYRO_XOUT_H,buff,6)<0);
        
    Data[3]=(buff[0] << 8)|buff[1];
	Data[4]=(buff[2]<<8)|buff[3];
    Data[5]=(buff[4]<<8)|buff[5];
    ret = copy_to_user(buffer,Data,sizeof(Data));
    

    return 0;
}
/**
  * @brief   读取MPU6050的ID
  * @param   
  * @retval  正常返回1，异常返回0
  */
uint8_t MPU6050ReadID(struct i2c_client *client)
{
	unsigned char Re = 0;
    mpu6050_readByte(mpu6050.client,MPU6050_WHO_AM_I,&Re);    //读器件地址
	if(Re != 0x68)
	{
		printk("MPU6050 dectected error!\r\n检测不到MPU6050模块，请检查模块与开发板的接线\r\n");
		return 0;
	}
	else
	{
		printk("MPU6050 ID = %d\r\n",Re);
		return 1;
	}
		
}
/**
  * @brief   初始化MPU6050芯片
  * @param   
  * @retval  
  */
void MPU6050_Init(struct i2c_client *client)
{
	//在初始化之前要延时一段时间，若没有延时，则断电后再上电数据可能会出错
	mpu6050_writeByte(client,MPU6050_PWR_MGMT_1, 0x00);
	mpu6050_writeByte(client,MPU6050_PWR_MGMT_2, 0x00);
	mpu6050_writeByte(client,MPU6050_SMPLRT_DIV, 0x07);
	mpu6050_writeByte(client,MPU6050_CONFIG, 0x06);
	mpu6050_writeByte(client,MPU6050_GYRO_CONFIG, 0x18);
	mpu6050_writeByte(client,MPU6050_ACCEL_CONFIG, 0x18);
	// mpu6050_writeByte(client,MPU6050_PWR_MGMT_1, 0x00);	    //解除休眠状态
	// mpu6050_writeByte(client,MPU6050_SMPLRT_DIV , 0x07);	    //陀螺仪采样率
	// mpu6050_writeByte(client,MPU6050_CONFIG , 0x06);	
	// mpu6050_writeByte(client,MPU6050_ACCEL_CONFIG , 0x01);	  //配置加速度传感器工作在16G模式
	// mpu6050_writeByte(client,MPU6050_GYRO_CONFIG, 0x18);     //陀螺仪自检及测量范围，典型值：0x18(不自检，2000deg/s)

}
static const struct file_operations mpu6050_fop={
    .write=mpu6050_write,
    .read=mpu6050_read,
    .open = mpu6050_open,
    .release=mpu6050_release,
    .owner = THIS_MODULE,
};


static int mpu6050_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
	/* 初始化MPU6050 */
    mpu6050.client=client;
    
    printk("probe!\r\n");
    int i=0;
    MPU6050_Init(client);
    if(MPU6050ReadID(client)==0)
        return -1;
    return 0;
}

static int mpu6050_i2c_remove(struct i2c_client *client)
{
    printk("remove success!\r\n"); 
    return 0;
}

static const struct of_device_id mpu6050_driver_ids[] = {
	{ .compatible = "ext,mpu6050" },
	{ }
};
static const struct i2c_device_id  mpu6050_id_table[]={
    {"ext,mpu6050", 0},
    { }
};
static struct i2c_driver mpu6050_driver = {
	.driver = {
		.name = MPU6050_NAME,
		.owner = THIS_MODULE,
		.of_match_table = mpu6050_driver_ids,
	},
	.probe = mpu6050_i2c_probe,
    .remove = mpu6050_i2c_remove,
    .id_table = mpu6050_id_table,
};



static int __init mpu6050_init(void)
{
    int ret = 0;
    if(mpu6050.major)
    {
        mpu6050.devid = MKDEV(mpu6050.major,mpu6050.minor);
        ret = register_chrdev_region(mpu6050.devid,MPU6050_NUM,MPU6050_NAME);
    }
    else
    {
        ret = alloc_chrdev_region(&mpu6050.devid,0,MPU6050_NUM,MPU6050_NAME);
    }
    if(ret<0)
    {
        printk("register chrdev error!\r\n");
        goto free_register; 
    }
    mpu6050.major=MAJOR(mpu6050.devid);
    mpu6050.minor = MINOR(mpu6050.devid);
    printk("major:%d\r\nminor:%d\r\n",mpu6050.major,mpu6050.minor);


    cdev_init(&mpu6050.mpu6050_cdev,&mpu6050_fop);
    ret = cdev_add(&mpu6050.mpu6050_cdev,mpu6050.devid,MPU6050_NUM);
    if(ret<0)
    {
        printk("cdev add error!\r\n");
        goto free_cdev;
    }

    mpu6050.class = class_create(THIS_MODULE,MPU6050_NAME);
    if(IS_ERR(mpu6050.class))
    {
        printk("class creat error!\r\n");
        goto free_class;
    }

    mpu6050.device = device_create(mpu6050.class,NULL,mpu6050.devid,NULL,MPU6050_NAME);
    if(IS_ERR(mpu6050.device))
    {
        printk("device creat error!\r\n");
        goto free_device;
    }

  return  i2c_add_driver(&mpu6050_driver);


free_device:
    device_destroy(mpu6050.class,mpu6050.devid);
free_class:
    class_destroy(mpu6050.class);
free_cdev:
    cdev_del(&mpu6050.mpu6050_cdev);
free_register:
    unregister_chrdev_region(mpu6050.devid,MPU6050_NUM);
    return -1;
}

static void __exit mpu6050_exit(void)
{
    i2c_del_driver(&mpu6050_driver);
    device_destroy(mpu6050.class,mpu6050.devid);
    class_destroy(mpu6050.class);
    cdev_del(&mpu6050.mpu6050_cdev);
    unregister_chrdev_region(mpu6050.devid,MPU6050_NUM);
}

module_init(mpu6050_init);
module_exit(mpu6050_exit);
MODULE_ALIAS("xiao");
MODULE_LICENSE("GPL");
